package com.huixh.train.member.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.huixh.train.common.resp.MemberLoginResp;
import com.huixh.train.common.enums.BusinessType;
import com.huixh.train.common.exception.BusinessException;
import com.huixh.train.common.exception.BusinessExceptionEnum;
import com.huixh.train.member.domain.Member;
import com.huixh.train.member.domain.MemberExample;
import com.huixh.train.member.domain.SmsVerificationCodes;
import com.huixh.train.member.domain.SmsVerificationCodesExample;
import com.huixh.train.member.mapper.MemberMapper;
import com.huixh.train.member.mapper.SmsVerificationCodesMapper;
import com.huixh.train.member.req.MemberLoginReq;
import com.huixh.train.member.req.MemberRegisterReq;
import com.huixh.train.member.service.MemberService;
import com.huixh.train.utils.random.SnowUtil;
import com.huixh.train.utils.security.JwtUtil;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * @author huixh
 */
@Service
public class MemberServiceImpl implements MemberService {
    private final Logger logger = LoggerFactory.getLogger(MemberServiceImpl.class);
    @Resource
    private SnowUtil snowUtil;
    @Resource
    private MemberMapper memberMapper;
    @Resource
    private SmsVerificationCodesMapper smsVerificationCodesMapper;
    @Resource
    private JwtUtil jwtUtil;

    /**
     * 注册
     *
     * @param memberRegisterReq mobile
     * @return Long
     */
    @Override
    public Long register(MemberRegisterReq memberRegisterReq) {
        Member memberDb = getMemberByMobile(memberRegisterReq.getMobile());
        if (ObjectUtil.isNotEmpty(memberDb)) {
            throw new BusinessException(BusinessExceptionEnum.MEMBER_MOBILE_EXISTS);
        }

        Member member = new Member();
        member.setId(System.currentTimeMillis());
        member.setMobile(memberRegisterReq.getMobile());
        memberMapper.insert(member);
        return member.getId();
    }

    /**
     * 发送验证码接口
     *
     * @param mobile mobile
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendCode(String mobile) {
        Member memberByMobile = getMemberByMobile(mobile);
        if (ObjectUtil.isNull(memberByMobile)) {
            Member member = new Member();
            member.setId(snowUtil.getSnowflakeToLong());
            member.setMobile(mobile);
            memberMapper.insert(member);
            logger.info("记录已存入：{}", JSON.toJSONString(member));
        }
        // 生成验证码
        String randomStr = RandomUtil.randomString(4);
        // 保存短信记录
        logger.info("生成短信验证码： {}", randomStr);
        // 发送短信
        logger.info("对接短信通道");
        // 手机号 短信验证码 有效期 是否已使用 业务类型 发送时间 使用时间
        SmsVerificationCodes verificationCodes = new SmsVerificationCodes();
        verificationCodes.setId(snowUtil.getSnowflakeToLong());
        verificationCodes.setPhoneNumber(mobile);
        verificationCodes.setVerificationCode(randomStr);
        verificationCodes.setValidityPeriod(300);
        verificationCodes.setIsUsed(false);
        verificationCodes.setBusinessType(BusinessType.LOGIN.getBusinessType());
        verificationCodes.setSendTime(new Date());
        smsVerificationCodesMapper.insert(verificationCodes);
        logger.info("保存短信记录:{}", JSON.toJSONString(verificationCodes));
    }

    /**
     * 用户登录
     *
     * @param memberLoginReq memberLoginReq
     */
    @Override
    public MemberLoginResp login(MemberLoginReq memberLoginReq) {
        String code = memberLoginReq.getCode();
        String mobile = memberLoginReq.getMobile();
        Member memberByMobile = getMemberByMobile(mobile);
        //todo 设置测试验证码用例
        if ("0713".equals(code)) {
            String token = jwtUtil.createToken(getMemberByMobile(mobile).getId(), memberByMobile.getMobile());
            MemberLoginResp loginResp = BeanUtil.copyProperties(memberByMobile, MemberLoginResp.class);
            loginResp.setToken(token);
            return loginResp;
        }
        if (ObjectUtil.isNull(memberByMobile)) {
            throw new BusinessException(BusinessExceptionEnum.MEMBER_MOBILE_NOT_EXISTS);
        }
        SmsVerificationCodes codesByMobile = getSmsVerificationCodesByMobile(mobile);

        if (!StrUtil.equalsIgnoreCase(code, codesByMobile.getVerificationCode())) {
            throw new BusinessException(BusinessExceptionEnum.MEMBER_MOBILE_CODE_ERROR);
        }

        SmsVerificationCodesExample codesExample = new SmsVerificationCodesExample();
        codesExample.createCriteria().andIdEqualTo(codesByMobile.getId());
        smsVerificationCodesMapper.updateByExample(codesByMobile, codesExample);
        MemberLoginResp loginResp = BeanUtil.copyProperties(memberByMobile, MemberLoginResp.class);
        String token = jwtUtil.createToken(memberByMobile.getId(), memberByMobile.getMobile());
        loginResp.setToken(token);
        return loginResp;
    }

    private Member getMemberByMobile(String mobile) {
        MemberExample memberExample = new MemberExample();
        memberExample.createCriteria().andMobileEqualTo(mobile);
        List<Member> list = memberMapper.selectByExample(memberExample);
        if (CollUtil.isEmpty(list)) {
            return null;
        } else {
            return list.get(0);
        }
    }

    /**
     * 通过手机号获取一个最新的验证码
     *
     * @param mobile 手机号
     * @return 验证码实体类
     */
    private SmsVerificationCodes getSmsVerificationCodesByMobile(String mobile) {
        SmsVerificationCodesExample codesExample = new SmsVerificationCodesExample();
        codesExample.createCriteria()
                .andPhoneNumberEqualTo(mobile)
                .andIsUsedEqualTo(false)
                .andBusinessTypeEqualTo(BusinessType.LOGIN.getBusinessType());
        codesExample.setOrderByClause("send_time desc");
        List<SmsVerificationCodes> verificationCodes = smsVerificationCodesMapper.selectByExample(codesExample);
        if (CollUtil.isEmpty(verificationCodes)) {
            throw new BusinessException(BusinessExceptionEnum.MEMBER_MOBILE_CODE_NOT_EXISTS_OR_EXPIRED);
        } else {
            SmsVerificationCodes newVerificationCodes = verificationCodes.get(0);
            Date sendTime = newVerificationCodes.getSendTime();
            long between = DateUtil.between(sendTime, new Date(), DateUnit.SECOND);
            if (between > newVerificationCodes.getValidityPeriod()) {
                throw new BusinessException(BusinessExceptionEnum.MEMBER_MOBILE_CODE_NOT_EXISTS_OR_EXPIRED);
            }

            newVerificationCodes.setIsUsed(true);
            newVerificationCodes.setUseTime(new Date());

            return newVerificationCodes;
        }
    }
}
